// Copyright 2009 Google Inc. All Rights Reserved.
package com.google.wave.extensions.polly;

import java.util.logging.Logger;

import com.google.wave.api.RobotMessageBundle;
import com.google.wave.api.Wavelet;

/**
 * Represents the persistent state of the poll stored in wave. This class
 * provides simple serialization/deserialization into a string. Data documents
 * can be arbitrary xml or string data.
 * 
 * @author scovitz@google.com (Seth Covitz)
 */
public class CaseMetadata {

  // Delimeter and separator constants.
  //private static final String LINE_SEP_REGEX = "\\n";
  //private static final String FIELD_SEP_REGEX = "\\:";

  private static final String METADATA_DOC = "case-metadata";
  private static final String METADATA_FIELD_SEP = "|";
  private static final String METADATA_FIELD_SEP_REGEX = "\\|";
  //private static final String METADATA_ID_SEP = "$";
  //private static final String METADATA_ID_SEP_REGEX = "\\$";

  //private static final String NEWIDS_DOC = "_new_ids_";
  //private static final String NEWIDS_POLL_BLIP_PREFIX = "poll-blip-";
  
  //private static final String VOTES_DOC = "poll-votes";
  

  private String caseUrl = "-";
  private String caseNumber = "-";
  private String blipId = "-";
  
	private static final Logger LOG = Logger.getLogger(CaseyServlet.class.getName());
  
  
  /**
   * The previously stored title for an AdminWavelet or the distributed poll
   * title for a PollWavelet.
   */
  //private String title = "";
  
  /**
   * The AdminWavelet Id for PollWavelets to communicate their vote.
   */
  private String resultsWaveletId = "";

  /**
   * The serialized form of the data document to compare against to determine
   * changes. 
   */
  private String dataDocument = "";
  
  /**
   * The current robot context.
   */
  private RobotMessageBundle context;
  
  /**
   * Whether any of the poll metadata has changed (and should be saved).
   */
  private boolean hasChanged = true;
  
  /**
   * Constructs the previous state of the Admin or Poll wavelet from metadata
   * stored in a data document. 
   * 
   * @param context the context the robot is currently called with.
   */
  public CaseMetadata(RobotMessageBundle context) {
    this.context = context;
    loadMetadata();
  }

  /**
   * Deserializes the previous state of the poll metadata from the data stored
   * in the data document.
   */
  private void loadMetadata() {
	  LOG.warning("Loading case metadata...");
    this.dataDocument = context.getWavelet().getDataDocument(METADATA_DOC);
    if (dataDocument != null) {
    	LOG.warning("Metadata data document: " + dataDocument);
      try {
        String[] items = dataDocument.split(METADATA_FIELD_SEP_REGEX);
        if (items.length == 1) {
        	this.resultsWaveletId = items[0];
        } else {
	        this.caseNumber = items[0];
	        this.caseUrl = items[1];
	        this.resultsWaveletId = items[2];
	        this.blipId = items[3];
	        LOG.warning("Item 0: " + items[0]);
	        LOG.warning("Item 1: " + items[1]);
	        LOG.warning("Item 2: " + items[2]);
        }
      } catch(IndexOutOfBoundsException iobx) {
        // Receiving an exception means that the data document has not yet
        // been fully populated.
    	  LOG.warning("We found the exceptions handler for index out of bounds, even with the check for length in there.");
      }
      hasChanged = false;
    }
  }
  
  /**
   * Saves the poll metadata as a data document in the robot context's wavelet.
   */
  public void saveMetadata() {
	  LOG.warning("Saving case metadata...");
    saveMetadata(context.getWavelet());
  }
  
  public String serializeNewDocument() {
	    StringBuilder newDataDocument = new StringBuilder();
	    newDataDocument.append(caseNumber);
	    newDataDocument.append(METADATA_FIELD_SEP);
	    newDataDocument.append(caseUrl);
	    newDataDocument.append(METADATA_FIELD_SEP);
	    newDataDocument.append(resultsWaveletId);
	    newDataDocument.append(METADATA_FIELD_SEP);
	    newDataDocument.append(blipId);
	    return newDataDocument.toString();
  }
  
  /**
   * Serializes the state of the poll metadata to the given wavelet. If the
   * new data document happens to be unchanged (ie. a person voted with the
   * same vote twice), the data document is not saved.
   * 
   * @param wavelet the wavelet in which to persist the data document.
   */
  public void saveMetadata(Wavelet wavelet) {
    String newDataDocument = serializeNewDocument();
    //if (!newDataDocument.equals(dataDocument)) {
      wavelet.setDataDocument(METADATA_DOC, newDataDocument);
    //}
  }
  
  public void setBlipId(String blipId) {
	  this.blipId = blipId;
  }
  
  /**
   * Returns whether the metadata has changed. This can be caused by the
   * addition of new polls or votes, or the updating of metadata by changes in
   * the AdminWavelet.
   * 
   * @return true if the metadata has changed, false otherwise.
   */
  public boolean hasChanged() {
    return hasChanged;
  }


  public String getCaseNumber() {
	  return caseNumber;
  }
  
  public String getCaseUrl() {
	  return caseUrl;
  }

  public void setCaseNumber(String caseNumber) {
	  this.caseNumber = caseNumber;
	  hasChanged = true;
  }
  
  public void setCaseUrl(String caseUrl) {
	  this.caseUrl = caseUrl;
	  hasChanged = true;
  }
  
  /**
   * Sets the results wavelet id. This is used mainly by PollWavelets to
   * communicate back their votes. The results wavelet is synonymous with
   * the AdminWavelet.
   * 
   * @param resultsWaveletId
   */
  public void setResultsWaveletId(String resultsWaveletId) {
    this.resultsWaveletId = resultsWaveletId;
    hasChanged = true;
  }

  /**
   * Returns the results wavelet id. 
   * 
   * @return the results wavelet id.
   */
  public String getResultsWaveletId() {
    return resultsWaveletId;
  }

  public void writeCaseDataToResults(String caseNumber, String caseUrl) {
	  	LOG.warning("\nwriteCaseDataToResults\n" + resultsWaveletId + "\n\n");

	    String[] waveIdParts = resultsWaveletId.split(" ");
	    String waveId = waveIdParts[0];
	    String waveletId = waveIdParts[1];	  
	    Wavelet resultsWavelet = context.getWavelet(waveId, waveletId);
	  
	    resultsWavelet.setDataDocument(METADATA_DOC, caseNumber + METADATA_FIELD_SEP 
	    			+ caseUrl + METADATA_FIELD_SEP + resultsWavelet.getWaveletId());
	    saveMetadata();
  }
  
  /**
   * Constructs a string to identify the new poll wavelet id for a recipient.
   * Writebacks are necessary as the wavelet isn't created until the operation
   * is received by the RobotProxy server. In order to access a wavelet
   * without an event having been generated, one will need the id. Hence a
   * writeback mechanism is used as a notification of the newly created id once
   * it is available.
   * 
   * @param recipient
   * @return the key for the writeback id.
   */
  public String getPollWriteback(String recipient) {
    return recipient;
  }

}
